<?php
/**
 * 将文档解析为实体
 */

class Spider_DomParser_Entity {

    /**
     * 输出的编码
     * @var <type>
     */
    private $_charset = 'UTF-8';

    /**
     * parser 获取内容后继续加工的回调函数
     * @var <type>
     */
    private $_parseCallback = null;

    /**
     * 实体内容
     * @var <type>
     */
    private $_entity = array();

    /**
     * 规则
     * @var <type>
     */
    private $_rules = array();

    /**
     * 一些属性映射
     * @var <type>
     */
    private static $_attributeMapping = array(
        'text' => 'innertext',
        'html' => 'innertext',
        'className' => 'class',
        'innerHTML' => 'innertext',
        'outerHTML' => 'outertext',
    );

    /**
     * 构造函数
     * @param <type> $option
     */
    public function  __construct($option = array()) {

        if (!empty($option['charset'])) {
            $this->_charset = $option['charset'];
        }

        if (!empty($option['rules'])) {
            foreach ($option['rules'] as $field => $rule) {
                $this->addRule($field, $rule['selector'], $rule['attr'], isset($rule['default']) ? $rule['default'] : '');
            }
        }

        if (!empty($option['parse_callback'])) {
            $this->_parseCallback = $option['parse_callback'];
        }
    }

    /**
     * 添加规则
     * @param <type> $field
     * @param <type> $selector
     * @param <type> $attr
     * @param <type> $default
     */
    public function addRule($field, $selector, $attr, $default = '') {

        // 处理属性
        if (is_array($attr)) {
            $mappedAttr = array();
            foreach ($attr as $k => $f) {
                $mappedAttr[$k] = isset(self::$_attributeMapping[$f]) ? self::$_attributeMapping[$f] : $f;
            }
            $attr = $mappedAttr;
        } elseif (isset(self::$_attributeMapping[$attr])) {
            $attr = self::$_attributeMapping[$attr];
        }

        $this->_rules[$field] = array(
            'selector' => $selector,
            'attr' => $attr,
            'default' => $default,
        );
    }

    /**
     * 使用 parser 来解析 entity
     * @param Spider_DomParser_Abstract $parser
     * @return <type>
     */
    public function parse(Spider_DomParser $parser) {

        $this->_entity = array();

        // 按选择器获取内容
        foreach ($this->_rules as $field => $rule) {
            if (is_array($rule['selector'])) {
                $node = $parser->select($rule['selector'][0], $rule['selector'][1]);
                $this->_entity[$field] = $this->_fetchAttributes($node, $rule['attr'], $parser->charset);
                unset($node);
            } else {
                $nodes = $parser->select($rule['selector']);
                $this->_entity[$field] = array();
                foreach ($nodes as $node) {
                    $this->_entity[$field][] = $this->_fetchAttributes($node, $rule['attr'], $parser->charset);
                }
                unset($nodes);
            }
            if (empty($this->_entity[$field])) {
                $this->_entity[$field] = $rule['default'];
            }
        }

        // 回调处理
        if ($this->_parseCallback) {
            $this->_entity = call_user_func($this->_parseCallback, $this->_entity);
        }

        return $this->_entity;
    }

    /**
     * 获取节点值（如果 parser 的编码和需要输出的编码不一致，同时转换编码）
     * @param <type> $node
     * @param <type> $attr
     * @return <type>
     */
    private function _fetchAttributes($node, $attr, $sourceCharset = 'UTF-8') {

        if (!$node) {
            return '';
        }

        if (is_array($attr)) {
            $values = array();
            foreach ($attr as $k => $field) {
                $values[$k] = ($sourceCharset == $this->_charset) ? $node->{$field} : mb_convert_encoding($node->{$field}, $this->_charset, $sourceCharset);
            }
            return $values;
        } else {
            return ($sourceCharset == $this->_charset) ? $node->{$attr} : mb_convert_encoding($node->{$attr}, $this->_charset, $sourceCharset);
        }
    }
}
